<?php

/**
 * Holds class Mvc_Router
 *
 * @author Mark
 *
 * @package Library
 * @subpackage Mvc
 */

/**
 * Determines requested module, controller and action
 *
 * @author Mark
 */
class Mvc_Router {

	/**
	 * Base path
	 * @var string $_basePath
	 */
	protected $_basePath = '';

	/**
	 * Module path
	 * @var string $_modulePath
	 */
	protected $_modulePath = '';

	/**
	 * Request resource
	 * @var Mvc_Request $_request
	 */
	protected $_request;

	/**
	 * Site path
	 * @var string $_sitePath
	 */
	protected $_sitePath = '';

	/**
	 * Custom routes
	 * @var array $_route
	 */
	protected $_route = array();

	/**
	 * Constructor
	 *
	 * @param Mvc_Request $request
	 * @return void
	 */
	public function __construct(Mvc_Request $request) {
		$this->_request = $request;
	}

	/**
	 * Creates URI
	 *
	 * @param string $module
	 * @param string $controller
	 * @param string $action
	 * @param array $params (optional)
	 * @param boolean $custom (optional)
	 * @return string
	 */
//	public function createUri($module, $controller, $action, $params = array(), $custom = true) {
//		$uri = $module . '/' . $controller . '/' . $action;
//		foreach($params as $key => $value) {
//			$uri .= '/' . $key . '/' . $value;
//		}
//
//		// Check if route is defined as custom
//		$key = false;
//		if($custom) {
//			$key = array_search($uri, $this->_route);
//		}
//		return (false !== $key) ? $this->_sitePath . $key : $this->_sitePath . $uri;
//	}

	/**
	 * Routes request
	 *
	 * @return string
	 */
	public function route() {
		$uri = str_replace('\\', '/', $this->_request->getServer('REQUEST_URI'));
		$uri = rtrim($uri, '/') . '/';
		if(0 != strlen($this->_basePath) && 0 === strpos($uri, $this->_basePath)) {
			$uri = substr($uri, strlen($this->_basePath));
		}
		
		$uri = trim($uri, '/');
		
//		@list($first,$rest) = @explode('/',$uri,2);
		
		// Check for defined routes
		$uri = $this->_matchRoute($uri);
//		$uri = $this->_matchRoute($first) . $rest;
		
		$uri = trim($uri, '/');

		// Fill request
		$param = explode('/', $uri);

		// Check if array is filled
		if(isset($param[0]) && '' == $param[0]) {
			$param = array();
		}

		// Critical parameters
		if(false !== current($param)) {
			$this->_request->setModule(array_shift($param));
		}
		if(false !== current($param)) {
			$this->_request->setController(array_shift($param), $this->_modulePath);
		}
		if(false !== current($param)) {
			$this->_request->setAction(array_shift($param));
		}

		// Additional parameters
		while(false !== current($param)) {
			$key   = array_shift($param);
			$value = null;
			if(false !== current($param)) {
				$value = utf8_decode(urldecode(array_shift($param)));
			}
			
			$this->_request->setParam($key, $value);
		}

		return $this->_modulePath . $this->_request->getModule() . DIRECTORY_SEPARATOR . $this->_request->getController() . '.php';
	}

	/**
	 * Sets base path
	 *
	 * @param string $path
	 * @return Mvc_Router (fluent interface)
	 */
	public function setBasePath($path) {
		$this->_basePath = DIRECTORY_SEPARATOR . trim($path, '\\/') . DIRECTORY_SEPARATOR;
		return $this;
	}

	/**
	 * Sets default request
	 *
	 * @param array $default
	 * @return Mvc_Router (fluent interface)
	 */
	public function setDefault(array $default) {
		if(isset($default['module'])) {
			$this->_request->setModule($default['module']);
		}
		if(isset($default['controller'])) {
			$this->_request->setController($default['controller']);
		}
		if(isset($default['action'])) {
			$this->_request->setAction($default['action']);
		}
		return $this;
	}

	/**
	 * Sets module path
	 *
	 * @param string $path
	 * @return Mvc_Router (fluent interface)
	 */
	public function setModulePath($path) {
		$this->_modulePath = rtrim($path, '\\/') . DIRECTORY_SEPARATOR;
		return $this;
	}

	/**
	 * Sets custom route
	 *
	 * @param array|string $src
	 * @param string $dest
	 * @return Mvc_Router (fluent interface)
	 */
	public function setRoute($src, $dest = null) {
		if(is_array($src)) {
			$this->_route = array_merge($this->_route, $src);
		}
		else {
			$this->_route[$src] = $dest;
		}
		return $this;
	}

	/**
	 * Sets site path
	 *
	 * @param string $sitePath
	 * @return Mvc_Router (fluent interface)
	 */
//	public function setSitePath($sitePath) {
//		$this->_sitePath = rtrim($sitePath, '\\/') . '/';
//		return $this;
//	}

	/**
	 * Matches route
	 *
	 * @param string $uri
	 * @return string
	 */
	protected function _matchRoute($uri) {
		$keys = array_keys($this->_route);
		for($i=0,$n=count($keys);$i<$n;$i++){
			if($keys[$i] !== "_default"){
				if(preg_match($keys[$i],$uri)){
					return preg_replace($keys[$i],$this->_route[$keys[$i]],$uri)."/";
				}
			}
		}
		
		// Match plain
		if(isset($this->_route[$uri])) {
			return $this->_route[$uri] . '/';
		}
//		return '';
		return $uri . '/';
	}

}
